package cni

import (
	"context"
	"encoding/json"
	"mediumkube/pkg/common"

	"github.com/containerd/containerd"
	gocni "github.com/containerd/go-cni"
	"k8s.io/klog/v2"
)

const (
	cniConfPath      = "/etc/mediumkube/conf/net.d"
	cniBinPath       = "/usr/local/mediumkube/bin"
	bridgePluginName = "mediumkube-bridge"
)

func confDir() string {
	return cniConfPath
}

func binDIr() string {
	return cniBinPath
}

func loadConfig(ext common.Extension) ([]byte, error) {
	cfg := NewConfig(ext)
	return json.Marshal(&cfg)
}

// https://www.cni.dev/plugins/v0.7/main/bridge/
func GetBridgePlugin(ext common.Extension) (gocni.CNI, error) {
	cni, err := gocni.New(
		gocni.WithMinNetworkCount(1),
		gocni.WithPluginConfDir(confDir()),
		gocni.WithPluginDir([]string{binDIr()}),
		gocni.WithInterfacePrefix("mediumkube"),
	)
	if err != nil {
		return nil, err
	}

	cfgBytes, err := loadConfig(ext)
	if err != nil {
		return nil, err
	}

	err = cni.Load(gocni.WithConf(cfgBytes))
	if err != nil {
		return nil, err
	}
	return cni, nil

}

// ApplyBridgePlugin to a given container
// Id should be unique for each container-plugin combination
// In mediumkube's context, should be extensionName-plugin pair
func ApplyBridgePlugin(ctx context.Context, netns string, container containerd.Container, ext common.Extension, labels map[string]string) (*gocni.Result, error) {
	cni, err := GetBridgePlugin(ext)
	if err != nil {
		return nil, err
	}
	klog.Infof("Running CNI for container in network namespace %s", netns)
	res, err := cni.Setup(ctx, ext.BridgeCNIID(), netns, gocni.WithLabels(labels))
	if err != nil {
		return nil, err
	}
	klog.Info("Details\n")
	return res, nil
}

func CleanUPCNI(ctx context.Context, netns string, ext common.Extension) {
	cni, err := GetBridgePlugin(ext)
	if err != nil {
		klog.Warning(err)
	}
	err = cni.Remove(ctx, ext.BridgeCNIID(), netns)
	if err != nil {
		klog.Warning(err)
	}
}
